<template>
	<SlotModal ref='slotModalRef' v-bind='slotModalConfig'>
		<n-form ref='formRef' v-bind='formConfig'
				:model='formData' :rules='formRules'>
			<n-grid :x-gap='24' :cols='2'>
				<n-form-item-grid-item span='1' label='角色编码' path='roleCode'>
					<n-input v-model:value='formData.roleCode' placeholder='请输入角色编码'
							 clearable/>
				</n-form-item-grid-item>
				<n-form-item-grid-item span='1' label='角色名称' path='roleName'>
					<n-input v-model:value='formData.roleName' placeholder='请输入角色名称'
							 clearable/>
				</n-form-item-grid-item>
				<n-form-item-grid-item span='1' label='角色特征' path='roleFeatures'>
					<n-select v-model:value='formData.roleFeatures'
							  :options='optionList.roleFeatures.list'
							  :loading='optionList.roleFeatures.loading'
							  :disabled='optionList.roleFeatures.disabled'
							  placeholder='请选择角色特征'
							  virtual-scroll filterable clearable>
					</n-select>
				</n-form-item-grid-item>
				<n-form-item-grid-item span='1' label='角色序号' path='sort'>
					<n-input-number v-model:value='formData.sort'
									style='width:100%' min='0' clearable/>
				</n-form-item-grid-item>
				<n-form-item-grid-item span='2' label='是否启用' path='status'>
					<n-switch v-model:value='formData.status as string' size='large'
							  :checkedValue='true'
							  :uncheckedValue='false'>
						<template v-slot:checked>启用</template>
						<template v-slot:unchecked>禁用</template>
					</n-switch>
				</n-form-item-grid-item>
				<n-form-item-grid-item span='2' label='该角色可访问的菜单' path='menuList'>
					<div class='menuList'>
						<n-flex>
							<n-button text round @click='allCheckOrAllUnCheck'>
								全选/全不选
							</n-button>
							<n-checkbox v-model:checked='treeConfig.cascade' label='级联'/>
						</n-flex>
						<n-input v-model:value='treeConfig.pattern' placeholder='请输入菜单名称(模糊匹配)'
								 clearable/>
						<!--带模糊搜索,级联,带勾选,虚拟滚动,默认展开全部,带禁用的Tree-->
						<n-tree ref='menuTree' v-bind='treeConfig'/>
					</div>
				</n-form-item-grid-item>
				<n-grid-item span='2' :show-feedback='false'>
					<n-flex justify='center' align='center'
							:wrap='false' inline style='width:100%;'>
						<n-button type='primary' @click='submitEvent'>
							提交
						</n-button>
						<n-button type='info' @click='resetEvent'>
							重置
						</n-button>
					</n-flex>
				</n-grid-item>
			</n-grid>
		</n-form>
	</SlotModal>
</template>
<script lang='ts' setup>
import { defineAsyncComponent, onMounted, PropType, reactive, ref } from 'vue';
// axios
import axios from '@/config/axios/index.ts';
// 模态框和打印组件
import { VxeUI } from '@/config/vxe/index.ts';
import type { JsonResultProps } from '#/JsonResult.d.ts';
import { FormInst, FormProps, FormRules, FormValidationError, NTree, TreeOption, TreeProps } from 'naive-ui';
import type { RoleProps } from '#/Role.d.ts';
import type { Options } from '#/Options.d.ts';
const SlotModal = defineAsyncComponent(() => import('@/components/customComponents/modal/SlotModal.vue'));
// 接收的参数
const props = defineProps({
	reLoad     : {
		type    : Function,
		require : true,
		default : null
	},
	optionList : {
		type    : Object as PropType<Options>,
		require : true,
		default : () => {
			return {
				roleFeatures : {
					loading  : true,
					disabled : true,
					list     : [],
					map      : {}
				}
			};
		}
	}
});
// ----------------------------------------------------------------------
const slotModalConfig = reactive({
	reLoad            : () => props.reLoad(),
	onCloseModalEvent : () => resetEvent(),
	resetEvent        : () => resetEvent()
});
// ----------------------------------------------------------------------
const formConfig = reactive<FormProps>({
	labelWidth           : 'auto',
	labelAlign           : 'left',
	labelPlacement       : 'left',
	size                 : 'large',
	requireMarkPlacement : 'right-hanging'
});
const formRules = reactive<FormRules>({
	roleCode     : {
		required : true,
		type     : 'string',
		trigger  : ['input', 'blur'],
		message  : '请输入角色编码'
	},
	roleName     : {
		required : true,
		type     : 'string',
		trigger  : ['input', 'blur'],
		message  : '请输入角色名称'
	},
	roleFeatures : {
		required : true,
		type     : 'string',
		trigger  : ['input', 'blur'],
		message  : '请选择角色特性'
	},
	sort         : {
		required : true,
		type     : 'number',
		trigger  : ['input', 'blur'],
		message  : '请输入角色序号'
	},
	status       : {
		required : true,
		type     : 'boolean',
		trigger  : ['input', 'blur'],
		message  : '请切换启用/禁用'
	}
});
const formData = reactive<Partial<RoleProps>>({});
// ----------------------------------------------------------------------
const slotModalRef = ref<InstanceType<typeof SlotModal>>();
const formRef = ref<FormInst>();
// ----------------------------------------------------------------------
const menuTree = ref<InstanceType<typeof NTree>>();
const treeConfig = reactive<TreeProps>({
	pattern             : '',
	showLine            : true,
	animated            : true,
	blockLine           : true,
	cascade             : true,
	selectable          : false,
	multiple            : false,
	checkable           : true,
	defaultExpandAll    : true,
	expandOnClick       : true,
	virtualScroll       : true,
	keyField            : 'menuCode',
	labelField          : 'menuName',
	disabledField       : 'disabled',
	childrenField       : 'children',
	checkedKeys         : [],
	data                : [],
	onUpdateCheckedKeys : (keys, option, meta) => onUpdateCheckedKeys(keys, option, meta)
});
// ----------------------------------------------------------------------
onMounted(async () => {
});
const showModal = async () => {
	await slotModalRef.value!.openModal({
		height     : '500',
		width      : '700',
		title      : '新增',
		showClose  : true,
		showZoom   : true,
		fullscreen : false
	});
	// 查询启用的菜单列表
	await getMenuList();
};
const resetEvent = async () => {
	// 清空搜索栏
	treeConfig.pattern = '';
	// 还原级联复选框
	treeConfig.cascade = false;
	// 清空已选菜单
	treeConfig.checkedKeys = [];
	// 清理表单数据
	Object.assign(formData, {
		tenantCode   : sessionStorage.getItem('loginTenantCode'),
		roleCode     : null,
		roleName     : null,
		roleFeatures : null,
		sort         : null,
		status       : '1',
		menuList     : []
	});
	// 去除表单校验提示
	formRef.value?.restoreValidation();
};
const submitEvent = async () => {
	// 校验菜单
	formRef.value?.validate((errors?: Array<FormValidationError>): void => {
		if (errors) {
			VxeUI.modal.message({ content : '请先完善填写的内容!', status : 'warning', id : 'validateMessage' });
		} else {
			const checkedKeys = menuTree.value?.getCheckedData().keys ?? [];
			const indeterminateKeys = menuTree.value?.getIndeterminateData().keys ?? [];
			formData.menuList = [...checkedKeys, ...indeterminateKeys];
			// 提交数据
			axios<any, JsonResultProps<any>, any>({
				method : 'POST',
				url    : '/role/add',
				data   : formData
			}).then((jsonResult: JsonResultProps<any>) => {
				if (jsonResult['status']) {
					// 提示用户
					VxeUI.modal.message({
						content : jsonResult['msg'],
						status  : 'success',
						id      : 'successMessage'
					});
					// 刷新数据
					props.reLoad();
					slotModalRef.value!.closeModal();
				} else {
					VxeUI.modal.message({
						content : jsonResult['msg'],
						status  : 'warning',
						id      : 'failedMessage'
					});
				}
			}).catch((error: unknown) => {
				console.error(error);
				VxeUI.modal.message({
					content : '系统异常,请稍后再试',
					status  : 'error',
					id      : 'errorMessage'
				});
			});
		}
	});
};
const getMenuList = async () => {
	axios<any, JsonResultProps<any>, any>({
		method : 'GET',
		url    : '/menu/menuTree'
	}).then((jsonResult: JsonResultProps<any>) => {
		if (jsonResult.status) {
			treeConfig.data = jsonResult.data;
		}
	}).catch((error: unknown) => {
		console.error(error);
		VxeUI.modal.message({
			content : '系统异常,请稍后再试',
			status  : 'error',
			id      : 'errorMessage'
		});
	});
};
const onUpdateCheckedKeys = async (
	keys: Array<string | number>,
	option: Array<TreeOption | null>,
	meta: { node: TreeOption | null, action: 'check' | 'uncheck' }
) => {
	treeConfig.checkedKeys = keys;
};
const allCheckOrAllUnCheck = async () => {
	const checkedFlag = treeConfig.checkedKeys && Array.isArray(
		treeConfig.checkedKeys) && treeConfig.checkedKeys.length;
	if (checkedFlag) {
		treeConfig.checkedKeys = [];
	} else {
		treeConfig.checkedKeys = getAllKeys(treeConfig.data as Array<TreeOption>);
	}
};
const getAllKeys = (nodeList: Array<TreeOption>) => {
	let keys: Array<any> = [];
	nodeList?.forEach(node => {
		if (!node!.disabled) {
			keys.push(node!.menuCode);
		}
		const isChildren = node!.children && Array.isArray(node!.children) && node!.children.length;
		if (isChildren) {
			keys = keys.concat(getAllKeys(node!.children as Array<TreeOption>));
		}
	});
	return keys;
};
// 导出方法
defineExpose({ showModal });
</script>
<style lang='scss' scoped>
.menuList{
	box-sizing    :border-box;
	margin        :0;
	padding       :0;
	border        :0;
	height        :300px;
	width         :100%;
	display       :flex;
	flex-flow     :column nowrap;
	place-content :flex-start flex-start;
	place-items   :center center;
	place-self    :center center;
}
</style>